package cn.mrcode.wxsdk.core.dialogue.common.httpClient;

import cn.mrcode.wxsdk.core.context.ConfigContext;
import cn.mrcode.wxsdk.core.context.SdkContexts;
import cn.mrcode.wxsdk.core.dialogue.common.LogUtil;
import cn.mrcode.wxsdk.core.dialogue.common.PublicAccount;
import cn.mrcode.wxsdk.core.dialogue.common.exception.ReqException;
import cn.mrcode.wxsdk.core.dialogue.common.exception.SdkGlobalCode;
import cn.mrcode.wxsdk.core.dialogue.common.util.HttpKit;
import cn.mrcode.wxsdk.core.dialogue.service.BaseService;
import com.ning.http.client.AsyncHttpClient;
import com.ning.http.client.AsyncHttpClientConfig;
import com.ning.http.client.AsyncHttpClientConfigBean;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.ssl.SSLContexts;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.SSLContext;
import java.io.InputStream;
import java.security.KeyStore;
import java.util.HashMap;
import java.util.Map;

/**
 * @author zhuqiang
 * @version V1.0
 * @date 2015/11/2 11:15
 */
public class DefeatHttpClient implements IHttpClinet {
    protected  /*static*/ AsyncHttpClient http = new AsyncHttpClient();
    protected /*static*/ HashMap<String,AsyncHttpClient> sslHttpMap = new HashMap<String,AsyncHttpClient>(); //保存公众账户对应的证书请求器
    protected /*static*/ Logger LOG = LoggerFactory.getLogger(DefeatHttpClient.class);

    public DefeatHttpClient() {
        ConfigContext configContext = SdkContexts.getConfigContext();
        // 在手动更新的时候 暂时并不需要初始化ssl请求器
        if(configContext != null){
            HashMap<String, PublicAccount> payPublicAccountMap = configContext.getPayPublicAccountMap();
            if(payPublicAccountMap != null && payPublicAccountMap.size() > 0){
                sslHttpInit(payPublicAccountMap);
            }
        }
    }

    /**
     * 初始化需要托管的 支付ssl请求器
     * @param payPublicAccountMap
     */
    private void sslHttpInit(HashMap<String, PublicAccount> payPublicAccountMap){
        LOG.info("开始构建ssl证书");
        if(payPublicAccountMap != null && payPublicAccountMap.size() > 0){
            for(Map.Entry<String, PublicAccount> ent:payPublicAccountMap.entrySet()){
                String appid = ent.getKey();
                PublicAccount account = ent.getValue();
                try {
                    AsyncHttpClientConfig.Builder builder = new AsyncHttpClientConfigBean.Builder();
                    KeyStore keyStore = KeyStore.getInstance("PKCS12");
                    InputStream instream = BaseService.class.getResourceAsStream(account.getCertLocalPath());
                    try {
                        keyStore.load(instream, account.getCertPassword().toCharArray());
                    } finally {
                        instream.close();
                    }
                    // Trust own CA and all self-signed certs
                    SSLContext sslcontext = SSLContexts.custom()
                            .loadKeyMaterial(keyStore, account.getCertPassword().toCharArray())
                            .build();
                    builder.setSSLContext(sslcontext);
                    AsyncHttpClientConfig config = builder.build();
                    sslHttpMap.put(appid,new AsyncHttpClient(config));
                } catch (Exception e) {
                    String info = String.format("构建证书失败:appid=%s", appid);
                    LOG.error(info);
                    throw new RuntimeException(info);
                }
            }
        }
    }

    @Override
    public String get(String url)throws ReqException {
        String result = null;
        try {
            result = HttpKit.get(http, url);
        } catch (Exception e) {
            LOG.error(LogUtil.fromateLog(SdkGlobalCode.REQ_10000));
            throw new ReqException(SdkGlobalCode.REQ_10000, e);
        }
        return result;
    }

    @Override
    public String postJson(String url, String body) throws ReqException {
        String result = null;
        try {
            result = HttpKit.post(http, url, body);
        } catch (Exception e) {
            LOG.error(LogUtil.fromateLog(SdkGlobalCode.REQ_10000));
            throw new ReqException(SdkGlobalCode.REQ_10000, e);
        }
        return result;
    }

    @Override
    public String postXml(String url, String xml, String appid) throws ReqException {
        String result = null;
        try {
            if(StringUtils.isNotBlank(appid)){
                AsyncHttpClient sslHttp = sslHttpMap.get(appid);
                if(sslHttp == null){
                    LOG.error(LogUtil.fromateLog(SdkGlobalCode.REQ_10001));
                    throw new ReqException(SdkGlobalCode.REQ_10001);
                }
                result = HttpKit.postXml(sslHttp, url, xml);
            }else{
                result = HttpKit.postXml(http, url, xml);
            }
        } catch (Exception e) {
            if(e instanceof ReqException){
                throw (ReqException)e;
            }else{
                LOG.error(LogUtil.fromateLog(SdkGlobalCode.REQ_10000));
                throw new ReqException(SdkGlobalCode.REQ_10000, e);
            }
        }
        return result;
    }
}
